#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <string.h>
#include <linux/fb.h>
#include <math.h>
#include<wchar.h>
#include <ft2build.h>
#include <freetype/ftcolor.h>

#include FT_FREETYPE_H
#include FT_GLYPH_H

unsigned char *fbmem;
unsigned char *hzkmem;

struct fb_var_screeninfo fb_var;
struct fb_fix_screeninfo  fb_fix;

unsigned int screensize;
#define FONTDATAMAX 4096

/*rgb565*/
void pixel_show(int x,int y, unsigned int color)
{
       unsigned int red,green,blue;
       switch(fb_var.bits_per_pixel)        //rgb   像素
       {
            case 32:
            {
                unsigned int  *addr=(unsigned int  *)fbmem+(fb_var.xres*y+x);
                *addr=color;   
                 break;
            }
            case 24:
           {
                unsigned int  *addr=(unsigned int  *)fbmem+(fb_var.xres*y+x);
                *addr=color;
                 break;
           }
           case 16:            //将RGB888 转为RGB565
           {
                unsigned short  *addr=(unsigned short  *)fbmem+(fb_var.xres*y+x);
                red   = (color >> 16) & 0xff;
                green = (color >> 8) & 0xff;
                blue  = (color >> 0) & 0xff;
                color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
                *addr = color;
                break;
           }
           case 8:
          {
               unsigned char  *addr=(unsigned char  *)fbmem+(fb_var.xres*y+x);     
               *addr = (unsigned char)color;
               break;
          }
          default:
         {
            printf("can't  surport %dbpp \n",fb_var.bits_per_pixel);
            break;
         }
       }
}

//如果background_color=0,那么不修改该位置的颜色
void draw_bitmap( FT_Bitmap* bitmap,
             FT_Int x,
             FT_Int y,
			 unsigned int font_color,
			 unsigned int background_color)
{
	FT_Int  i, j, p, q;  
    FT_Int  x_max = x + bitmap->width;        //x:当前X位置， bitmap->width:该字宽度
    FT_Int  y_max = y + bitmap->rows;

    for ( i = x, p = 0; i < x_max; i++, p++ )   //i:lcd的x轴
    {
		for ( j = y, q = 0; j < y_max; j++, q++ )  //j:lcd的y轴
		{
			if ( i < 0 || j < 0 || i >= fb_var.xres || j >= fb_var.yres )
				continue;
			if(bitmap->buffer[q * bitmap->width + p] == 0)
	  		{
				if(background_color != 0)
					pixel_show( i, j,  background_color);
	  		}
			else
			{
				pixel_show( i, j,  font_color);
			}
    }
  }
} 

unsigned int line_box_ymax=0;
unsigned int line_box_ymin=30000;

void lcd_vector_show(char *argv,wchar_t  *str[],unsigned int lines)
{
	FT_Glyph  glyph;
    FT_BBox   acbox;
    FT_Library    library;
    FT_Face       face;
    FT_GlyphSlot  slot;
    FT_Vector     pen;                    /* untransformed origin  */

    unsigned char error;
    unsigned int line_nums=0;              
    unsigned char  n,font_size;

    error = FT_Init_FreeType( &library );              /* initialize library */
    if(error)
    {
		printf("FT_Init_FreeType ERROR\n");
        return ;
    }
	error = FT_New_Face( library, argv, 0, &face ); /* create face object */
    if(error)
	{
		printf("FT_New_Face ERROR\n");
        return ;
    }
    slot = face->glyph;

    error = FT_Set_Pixel_Sizes( face, 0,48);     /* set character size */

    for(line_nums=0;line_nums<lines;line_nums++)
   	{
		/*设置笔记落下位置*/
		/*显示坐标(从LCD左上方显示3  行)
		 *x=0
         *y=fb_var.yres-24   (减24,是因为笛卡尔坐标以左下方开始计算坐标值的)
        */
		if(line_nums==0)
		{
			pen.x = 0* 64;
			pen.y = ( fb_var.yres-48 ) * 64;  
		}
		else
		{
			pen.x = 0* 64;
			pen.y-= (line_box_ymax - line_box_ymin )* 64;   //在上行的Y值上减去边框高
			/*清空标志位,因为上一行的ymin永远当前行小*/
			line_box_ymax=0;
			line_box_ymin=30000;
		}
    	for ( n = 0; n < wcslen(str[line_nums]); n++ )
		{
			FT_Set_Transform( face, 0, &pen );
			error = FT_Load_Char( face,str[line_nums][n], FT_LOAD_RENDER );
			if(error)
			{
				printf("FT_Load_Char ERROR\n"); 
				continue; 
			}
			FT_Get_Glyph( face->glyph, &glyph );                   //获取字形图像 的信息
			FT_Glyph_Get_CBox(  glyph,FT_GLYPH_BBOX_TRUNCATE,&acbox );     //获取此行文字的box

			if(acbox.yMax>acbox.yMin)
			{
				if(line_box_ymax<acbox.yMax)
				line_box_ymax=acbox.yMax;
				if(line_box_ymin>acbox.yMin)
				line_box_ymin=acbox.yMin;
			}

			if(line_nums == 0)
			{
				draw_bitmap( &slot->bitmap,
						slot->bitmap_left,
						fb_var.yres- slot->bitmap_top, 0xff0000, 0x00);  //字体颜色红色，背景透明
			}
			else if(line_nums == 1)
			{
				draw_bitmap( &slot->bitmap,
						slot->bitmap_left,
						fb_var.yres- slot->bitmap_top, 0x00ff00, 0xffff00);  //字体颜色绿色，黄色背景
			}
			else if(line_nums == 2)
			{
				draw_bitmap( &slot->bitmap,
						slot->bitmap_left,
						fb_var.yres- slot->bitmap_top, 0x0000ff, 0x00ff00);  //字体颜色蓝色，绿色背景
			}
			
			pen.x += slot->advance.x;
		}
 	}
    FT_Done_Face( face );
    FT_Done_FreeType( library ); 
}

int main(int argc,char **argv)
{
    int fd_fb,fd_hzk;

    wchar_t   *chinese_str[]={L"嵌入式george",L"abc 中国chinese",L"哈哈哈哈wqe"};  

    if ( argc != 2 )
    {
      printf ("usage: %s  font_file \n", argv[0] );
      return 0;
     }

    fd_fb=open("/dev/fb0", O_RDWR);
    if(fd_fb<0)
    {
        printf("can't open /dev/fb0 \n");
        return 0;
     }

    if(ioctl(fd_fb,FBIOGET_VSCREENINFO,&fb_var)<0)
    {
        printf("can't get var \n");
        return 0;
    }

   if(ioctl(fd_fb,FBIOGET_FSCREENINFO,&fb_fix)<0)
    {
        printf("can't get fix \n");
        return 0;
    }

    screensize=fb_var.xres*fb_var.yres*(fb_var.bits_per_pixel/8);       //显存大小
	printf("%d \n", screensize);

    fbmem =(unsigned char *)mmap(NULL,screensize, PROT_READ|PROT_WRITE,MAP_SHARED,
                  fd_fb, 0);  //映射fb0

    if(!fbmem)
    {
        printf("can't map /dev/fb0 \n");
        return 0;
    }

    memset(fbmem, 255, screensize);            //清屏白色

    /*显示3 行 矢量文字*/
    lcd_vector_show(argv[1], chinese_str,3);  

    munmap(fbmem,screensize);
    return 0;
}